<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>对象创建方法 原型 对象属性引用</title>
</head>
<body>
    <script>
        /*对象创建方式（对象有属性也有方法）*/

        //1.大括号方式（对象字面量方式）
        let  obj1={
            name: "Make",
            age: 24}
        console.log("大括号方式：",obj1)
        //另外添加个方法
        obj1.sayHi=function(){
            console.log(`你好！我是${this.name},我今年${this.age}岁了`)
        }
        obj1.sayHi()

        console.log("\n")
        
        //2.new Object()方式
        let obj2=new Object()
        obj2.name="Marry"
        obj2.age=23
        console.log("new Object()方式：", obj2)
        //另外添加个方法
        obj2.sayHello = function () {
                console.log(`你好！我是${this.name},我今年${this.age}岁了`)
            }
        //obj2.sayHello = () => console.log(`你好！我是${this.name},我今年${this.age}岁了`)
        //箭头函数不能用this进行绑定数据，因为在JavaScript中，箭头函数不会绑定自己的this，它会捕获其所在上下文的this值
        //因此要传入参数，进行包围
        obj2.sayHello1 = (name,age)=> console.log('你好！我是'+name+',我今年'+age+'岁了')
        obj2.sayHello()
        obj2.sayHello1(obj2.name,obj2.age)
        //这个只是调用了obj2的方法sayHello1打印出了这个信息，但是并不是obj2的信息，这个是错误的
        obj2.sayHello1("hi",5)
        //上面方法的调用并不影响obj2的对象信息
        console.log(obj2)

        console.log("\n")

        //3.构造函数【使用在ES5及之前】(构造函数遵循大驼峰命名)
        //[this. 指创建对象的值]
        function User(){
            this.name="Jon"
            this.age=16
        }
        let obj3=new User()
        console.log("构造函数方式：",obj3)

        function User1(name, age) {
                this.name = name
                this.age = age
            }
        User1.prototype.put = function () {
                console.log(`我的名字是${this.name}，我的年龄是${this.age}`)
            }
        obj3 = new User1("Amy", 16)
        obj3.put()

        function User2(x, y) {
                    this.name = x
                    this.age = y
                }
        obj3 = new User1("Anna", 8)
        console.log(obj3)

        console.log("\n")

        //4.Class 【ES6版本】：语法糖
        class Student3{
            //构造函数
            constructor(name,age){
                this.name=name
                this.age=age
                console.log(`我是${name}，今年${age}岁`)
            }

            //定义一个对象方法：该方式是放在此对象的原型上面的
            sayHello(){
                console.log("你好！")
                
            }
        }

        let s = new Student3("Make",12)
        console.log(s)
        s.sayHello()

        console.log("\n")
        
        //原型（protptype）:对象的原型是object，所有对象都有原型，一直到null
        //同一方式构造的两个对象：其原型一致，但是对象不一致（地址不同）
        class Student {
            // 构造函数
            constructor(name, age) {
                this.name = name 
                this.age = age 
                console.log("构造函数被调用了") 
            }

            // 定义方法
            sayHello() {
                console.log("你好！") 
            }
        }

        // 创建实例
        s = new Student("Jhon", 20) 
        console.log(s) 

        s1 = new Student("Amy", 18) 
        console.log(s1) 

        // 调用方法
        s.sayHello() 

        // 原型验证
        console.log(s.__proto__ === s1.__proto__) 
        //在原型上添加元素
        s.__proto__.height=247

        console.log("\n")


        /* 将对象方法放在原型（prototype）上的优势可总结为以下三点：
                1.‌内存优化‌：所有实例共享同一方法，避免重复创建，节省内存资源；
                2.‌性能提升‌：减少实例化时的计算开销，且现代引擎会缓存原型链查找；
                3.‌动态扩展‌：通过修改原型，可实时为所有实例添加或更新方法，无需重新生成实例。
           这一机制既符合JavaScript的原型设计模式，又能高效支持面向对象编程。 */



        //方法放在原型里共享示例如下：
        console.log("方法放在原型里共享示例①如下：")
        
        class Person2 {
        sayHi() {
            console.log(`Hi, I'm ${this.name} (${this.role})`) 
                }
        }

        class Student2 extends Person2 {
            constructor(name, grade) {
            super() 
            this.name = name 
            this.grade = grade 
            this.role = 'Student2' 
            }     
        }

        class Teacher2 extends Person2 {
        constructor(name, subject) {
            super() 
            this.name = name 
            this.subject = subject 
            this.role = 'Teacher2' 
        }
        }

        // 使用示例
        let stu = new Student2('Alice', 'A') 
        let tea = new Teacher2('Bob', 'Math') 
        stu.sayHi()  // 输出: Hi, I'm Alice (Student)
        tea.sayHi()  // 输出: Hi, I'm Bob (Teacher)

        console.log("\n")

        console.log("方法放在原型里共享示例②如下：")
        
        // 1. 创建基础构造函数（用于共享方法）
        function Person1() {}
        Person1.prototype.sayHi = function() {
            console.log(`Hi, I'm ${this.name} (${this.role})`) 
        }

        // 2. 创建具体对象构造函数
        function Student1(name, grade) {
        this.name = name 
        this.grade = grade 
        this.role = 'Student1' 
        }
        Student1.prototype = Object.create(Person1.prototype)  // 继承原型方法

        function Teacher1(name, subject) {
        this.name = name 
        this.subject = subject 
        this.role = 'Teacher1' 
        }
        Teacher1.prototype = Object.create(Person1.prototype)  // 继承原型方法

        // 3. 使用示例
        stu = new Student1('Alice', 'A') 
        tea = new Teacher1('Bob', 'Math') 
        stu.sayHi()  // 输出: Hi, I'm Alice (Student)
        tea.sayHi()  // 输出: Hi, I'm Bob (Teacher)

        console.log("\n")

        /*对象属性访问方式*/
        let obj={
            name:"张三",
            age:18
        }
        //1.键名访问
        console.log(obj["name"])
        //2.点名访问
        console.log(obj.name)
        
        
    </script>
</body>
</html>